// 2015年版权所有etcd作者
// 
// 根据Apache许可证2.0版（以下简称“许可证”）获得许可；
// 除非遵守许可证，否则不得使用此文件。
// 您可以通过
// 
// www.apache.org/licenses/LICENSE-2.0 
// 
// 除非适用法律要求或书面同意，否则根据许可证分发的软件
// 按“原样”分发，
// 无任何明示或暗示的保证或条件。
// 请参阅许可证，了解管理许可的特定语言和
// 许可证下的限制。

package v2stats

import (
	"encoding/json"
	"math"
	"sync"
	"time"

	"go.uber.org/zap"
)

// LeaderStats由etcd集群中的领导者使用，并封装了
// 与其追随者的通信统计
type LeaderStats struct {
	lg *zap.Logger
	leaderStats
	sync.Mutex
}

type leaderStats struct {
	// leader是etcd集群中领导者的ID。
	// TODO（jonboulle）：澄清这些是id，而不是名称
	Leader    string                    `json:"leader"`
	Followers map[string]*FollowerStats `json:"followers"`
}

// NewLeaderStats生成一个新的LeaderStats，其给定id为leader 
func NewLeaderStats(lg *zap.Logger, id string) *LeaderStats {
	if lg == nil {
		lg = zap.NewNop()
	}
	return &LeaderStats{
		lg: lg,
		leaderStats: leaderStats{
			Leader:    id,
			Followers: make(map[string]*FollowerStats),
		},
	}
}

func (ls *LeaderStats) JSON() []byte {
	ls.Lock()
	stats := ls.leaderStats
	ls.Unlock()
	b, err := json.Marshal(stats)
	// TODO（jonboulle）：正确的错误处理？
	if err != nil {
		ls.lg.Error("failed to marshal leader stats", zap.Error(err))
	}
	return b
}

func (ls *LeaderStats) Follower(name string) *FollowerStats {
	ls.Lock()
	defer ls.Unlock()
	fs, ok := ls.Followers[name]
	if !ok {
		fs = &FollowerStats{}
		fs.Latency.Minimum = 1 << 63
		ls.Followers[name] = fs
	}
	return fs
}

// FollowerStats封装了etcd集群中跟随者的各种统计信息
type FollowerStats struct {
	Latency LatencyStats `json:"latency"`
	Counts  CountsStats  `json:"counts"`

	sync.Mutex
}

// LatencyStats封装了延迟统计信息。
type LatencyStats struct {
	Current           float64 `json:"current"`
	Average           float64 `json:"average"`
	averageSquare     float64
	StandardDeviation float64 `json:"standardDeviation"`
	Minimum           float64 `json:"minimum"`
	Maximum           float64 `json:"maximum"`
}

// CountsStats封装raft统计信息。
type CountsStats struct {
	Fail    uint64 `json:"fail"`
	Success uint64 `json:"success"`
}

// 成功使用成功发送更新后续状态
func (fs *FollowerStats) Succ(d time.Duration) {
	fs.Lock()
	defer fs.Unlock()

	total := float64(fs.Counts.Success) * fs.Latency.Average
	totalSquare := float64(fs.Counts.Success) * fs.Latency.averageSquare

	fs.Counts.Success++

	fs.Latency.Current = float64(d) / (1000000.0)

	if fs.Latency.Current > fs.Latency.Maximum {
		fs.Latency.Maximum = fs.Latency.Current
	}

	if fs.Latency.Current < fs.Latency.Minimum {
		fs.Latency.Minimum = fs.Latency.Current
	}

	fs.Latency.Average = (total + fs.Latency.Current) / float64(fs.Counts.Success)
	fs.Latency.averageSquare = (totalSquare + fs.Latency.Current*fs.Latency.Current) / float64(fs.Counts.Success)

	// sdv=sqrt（avg（x^2）-avg（x）^2）
	fs.Latency.StandardDeviation = math.Sqrt(fs.Latency.averageSquare - fs.Latency.Average*fs.Latency.Average)
}

// 失败使用不成功发送更新后续状态
func (fs *FollowerStats) Fail() {
	fs.Lock()
	defer fs.Unlock()
	fs.Counts.Fail++
}
